﻿using NetTopologySuite.Geometries;
using NetTopologySuite.Simplify;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PointAsLine
{
    /// <summary>
    /// 直接首尾相连
    /// </summary>
    internal class ConnectHeadTrailer
    {
        internal static List<Polyline> Connect(List<Polyline> simplifiedSegments, double threshold)
        {
            for (var i = simplifiedSegments.Count - 1; i >= 0; i--)
            {
                var polyline = new Polyline(simplifiedSegments[i]);

                var p1 = polyline.Points[0];
                var p2 = polyline.Points[polyline.Points.Count - 1];
                if (PointFFunc.Distance(p1, p2) > threshold)
                {
                    continue;
                }

                var canConnect = true;
                /*for (var j = 0; j < polyline.Points.Count - 1; j++)
                {
                    var d2 = Distance(polyline.Points[j], polyline.Points[j + 1]);
                    if (d2 < 20)
                    {
                        continue;
                    }
                    if (SegmentsIntersect(p1, p2, polyline.Points[j], polyline.Points[j + 1]))
                    {
                        canConnect = false;
                        break;
                    }
                }*/
                if (canConnect)
                    polyline.Points.Add(p1);

                simplifiedSegments[i]=SimplifyLineByNetTopologySuite(polyline, 1);
            }
            return simplifiedSegments;
        }

        /// <summary>
        /// 使用 NetTopologySuite 的 Douglas-Peucker 算法简化线段
        /// </summary>
        /// <param name="points">原始点集</param>
        /// <param name="tolerance">简化容差（距离阈值）</param>
        /// <returns>简化后的点集</returns>
        public static Polyline SimplifyLineByNetTopologySuite(Polyline points, double tolerance)
        {
            // 1. 将 PointF 列表转换为 NetTopologySuite 的 Coordinate 列表
            var coordinates = points.Points.Select(p => new Coordinate(p.X, p.Y)).ToList();

            // 2. 创建 LineString 几何对象
            var lineString = new LineString(coordinates.ToArray());

            // 3. 使用 DouglasPeuckerSimplifier 进行简化
            var simplifiedLine = DouglasPeuckerSimplifier.Simplify(lineString, tolerance);

            // 4. 将简化后的坐标转换回 PointF 列表
            var simplifiedPoints = new List<PointF2G>();
            foreach (var coord in simplifiedLine.Coordinates)
            {
                simplifiedPoints.Add(new PointF2G((float)coord.X, (float)coord.Y));
            }

            return new Polyline(){ Points=simplifiedPoints,GroupIndex=points.GroupIndex };
        }

        /// <summary>
        /// 检查两条线段是否相交
        /// </summary>
        private static bool SegmentsIntersect(PointF p1, PointF p2, PointF p3, PointF p4)
        {
            // 计算方向
            float d1 = Direction(p3, p4, p1);
            float d2 = Direction(p3, p4, p2);
            float d3 = Direction(p1, p2, p3);
            float d4 = Direction(p1, p2, p4);

            // 如果线段跨立，则相交
            if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
                ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0)))
                return true;

            // 检查共线情况
            if (d1 == 0 && OnSegment(p3, p4, p1)) return true;
            if (d2 == 0 && OnSegment(p3, p4, p2)) return true;
            if (d3 == 0 && OnSegment(p1, p2, p3)) return true;
            if (d4 == 0 && OnSegment(p1, p2, p4)) return true;

            return false;
        }
 

        /// <summary>
        /// 计算三点方向
        /// </summary>
        private static float Direction(PointF pi, PointF pj, PointF pk)
        {
            return (pk.X - pi.X) * (pj.Y - pi.Y) - (pj.X - pi.X) * (pk.Y - pi.Y);
        }

        /// <summary>
        /// 检查点是否在线段上
        /// </summary>
        private static bool OnSegment(PointF pi, PointF pj, PointF pk)
        {
            return Math.Min(pi.X, pj.X) <= pk.X && pk.X <= Math.Max(pi.X, pj.X) &&
                   Math.Min(pi.Y, pj.Y) <= pk.Y && pk.Y <= Math.Max(pi.Y, pj.Y);
        }
    }
}
